package com.xzy.service.impl;

import com.xzy.common.base.PageableResult;
import com.xzy.common.util.PageFactory;
import com.xzy.domain.dto.NameCountDTO;
import com.xzy.domain.dto.UserDynamicQueryDTO;
import com.xzy.domain.dto.UserQueryDTO;
import com.xzy.domain.entity.UserEntity;
import com.xzy.repository.UserRepository;
import com.xzy.service.UserService;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @author xzy
 * @date 2021/11/1017:15
 */
@Service
public class UserServiceImpl implements UserService {
    private final MongoTemplate mongoTemplate;
    private final UserRepository userRepository;

    @Autowired
    public UserServiceImpl(MongoTemplate mongoTemplate, UserRepository userRepository) {
        this.mongoTemplate = mongoTemplate;
        this.userRepository = userRepository;
    }

    /**
     * 分页查询
     *
     * @param userQueryDTO - 查询、分页、排序条件
     * @return -
     */
    @Override
    public Page<UserEntity> findPageable(UserQueryDTO userQueryDTO) {
        // 分页、排序条件
        Pageable pageable = PageFactory.getPageable(userQueryDTO.getPageNumber(), userQueryDTO.getPageSize(), userQueryDTO.getSortDirection(), userQueryDTO.getSortBy());

        // 查询条件
        UserEntity userEntity = new UserEntity();
        BeanUtils.copyProperties(userQueryDTO, userEntity);
        Example<UserEntity> example = Example.of(userEntity);

        // 查询
        return userRepository.findAll(example, pageable);
    }

    /**
     * 按名称模糊查找
     *
     * @param name - 名称
     * @return -
     */
    @Override
    public List<UserEntity> findByNameLikely(String name) {

        /*
         * 完全匹配
         * Pattern pattern = Pattern.compile("^" + name + "$", Pattern.CASE_INSENSITIVE);
         *
         * 右匹配
         * Pattern pattern = Pattern.compile("^" + ".*" + name + "$", Pattern.CASE_INSENSITIVE);
         *
         * 左匹配
         * Pattern pattern = Pattern.compile("^" + name + ".*" + "$", Pattern.CASE_INSENSITIVE);
         */

        // 模糊匹配
        Pattern pattern3 = Pattern.compile("^" + ".*" + name + ".*" + "$", Pattern.CASE_INSENSITIVE);

        Query query = Query.query(Criteria.where("name").regex(pattern3));
        return mongoTemplate.find(query, UserEntity.class, "user");
    }

    /**
     * 按名称模糊查询，并进行排序、分页
     *
     * @param name     - 名称
     * @param pageNo   - 页码
     * @param pageSize - 页数据条数
     * @return -
     */
    @Override
    public Page<UserEntity> findByNameLikelyAndPageable(String name, Integer pageNo, Integer pageSize) {
        // 分页、排序条件
        Pageable pageable = PageFactory.getPageable(pageNo, pageSize, PageFactory.DESCENDING_UP, "name");

        return userRepository.findByNameLike(name, pageable);
    }

    /**
     * 动态 & 多条件 & 排序 & 分页 & 查询
     *
     * @param qc - 查询、排序、分页条件
     * @return - 查询结果
     */
    @Override
    public PageableResult<UserEntity> dynamicQuery(UserDynamicQueryDTO qc) {

        // 确认查询条件
        List<Criteria> queryConditions = new LinkedList<>();
        if (Strings.isNotEmpty(qc.getName())) {
            // 模糊匹配
            queryConditions.add(Criteria.where("name").regex(qc.getName()));
        }
        if (qc.getAge() != null) {
            // 精确匹配
            queryConditions.add(Criteria.where("age").is(qc.getAge()));
        }
        if (Strings.isNotEmpty(qc.getSex())) {
            queryConditions.add(Criteria.where("sex").is(qc.getSex()));
        }
        if (Strings.isNotEmpty(qc.getEmail())) {
            queryConditions.add(Criteria.where("email").regex(qc.getEmail()));
        }
        if (Strings.isNotEmpty(qc.getRemark())) {
            queryConditions.add(Criteria.where("remark").regex(qc.getRemark()));
        }
        if (qc.getCreateDateLeft() != null) {
            // 范围查询：大等于
            queryConditions.add(Criteria.where("createDate").gte(qc.getCreateDateLeft()));
        }
        if (qc.getCreateDateRight() != null) {
            // 范围查询：小等于
            queryConditions.add(Criteria.where("createDate").lte(qc.getCreateDateRight()));
        }

        // 整合查询条件
        Criteria queryCondition = new Criteria();
        if (!queryConditions.isEmpty()) {
            queryCondition.andOperator(queryConditions.toArray(new Criteria[0]));
        }
        Query query = Query.query(queryCondition);

        // 获取概要信息
        long docCount = mongoTemplate.count(query, UserEntity.class);
        long pageCount = (docCount % qc.getPageSize() == 0) ? (docCount / qc.getPageSize()) : (docCount / qc.getPageSize()) + 1;

        // 整合排序、分页条件
        Pageable pageable = PageFactory.getPageable(qc.getPageNo(), qc.getPageSize(), qc.getSortDirection(), qc.getSortField());
        query.with(pageable);

        // 获取分页数据
        List<UserEntity> result = mongoTemplate.find(query, UserEntity.class);

        return new PageableResult<UserEntity>()
                .setSortField(qc.getSortField())
                .setSortDirection(qc.getSortDirection())
                .setPageNo(qc.getPageNo())
                .setPageSize(qc.getPageSize())
                .setPageCount(pageCount)
                .setDocCount(docCount)
                .setResult(result);
    }

    /**
     * 统计各姓名的使用人数
     *
     * @param ageGte - 年龄（大于等于）
     * @param ageLte - 年龄（小于等于）
     * @return - 各姓名的使用人数
     */
    @Override
    public List<NameCountDTO> nameCount(Integer ageGte, Integer ageLte) {
        // 筛选条件、分组条件、排序条件
        MatchOperation matchOperation = Aggregation.match(
                Criteria.where("age")
                        .gte(ageGte)
                        .lte(ageLte)
        );
        GroupOperation groupOperation = Aggregation
                .group("name").count().as("count")
                .last("name").as("username");
        SortOperation sortOperation = Aggregation.sort(Sort.Direction.DESC, "count");

        // 查询数据
        Aggregation aggregation = Aggregation.newAggregation(matchOperation, groupOperation, sortOperation);
        AggregationResults<NameCountDTO> systemOpLogCounts = mongoTemplate.aggregate(aggregation, "user", NameCountDTO.class);
        return systemOpLogCounts.getMappedResults();
    }
}
